#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h> 
#include <linux/irq.h>
#include <linux/platform_device.h> 
#include <linux/miscdevice.h>
#include <linux/input.h>
#include <linux/i2c.h>

#define BMP180_NAME  "bmp180"
#define BMP180_NUM	 1
#define OSS_QUALITY  0

struct bmp180_st
{
	short ac1;
	short ac2; 
	short ac3; 
	unsigned short ac4;
	unsigned short ac5;
	unsigned short ac6;
	short b1; 
	short b2;
	short mb;
	short mc;
	short md;
	long  temperature;
	long  pressure;

	dev_t devID;
	int major;
	int minor;
	struct cdev cdev;
	struct class *class;
	struct device *device;
	struct device_node *node;
	struct i2c_client *client;
};
static struct bmp180_st bmp180;

static void bmp085Convert(struct bmp180_st *me, long ut, long up)
{
	long x1, x2, b5, b6, x3, b3, p;
	unsigned long b4, b7;
	
	x1 = ((long)ut - me->ac6) * (me->ac5) >> 15;
	x2 = ((long)(me->mc) << 11) / (x1 + me->md);
	b5 = x1 + x2;
	me->temperature = (b5 + 8) >> 4;
	
	b6 = b5 - 4000;
	x1 = (me->b2 * (b6 * b6 >> 12)) >> 11;
	x2 = (me->ac2) * b6 >> 11;
	x3 = x1 + x2;
	b3 = (((long)me->ac1 * 4 + x3) + 2)/4;
	x1 = me->ac3 * b6 >> 13;
	x2 = (me->b1 * (b6 * b6 >> 12)) >> 16;
	x3 = ((x1 + x2) + 2) >> 2;
	b4 = (me->ac4 * (unsigned long) (x3 + 32768)) >> 15;
	b7 = ((unsigned long) up - b3) * (50000 >> OSS_QUALITY);
	if( b7 < 0x80000000)
	    p = (b7 * 2) / b4 ;
    else  
		p = (b7 / b4) * 2;
	x1 = (p >> 8) * (p >> 8);
	x1 = (x1 * 3038) >> 16;
	x2 = (-7357 * p) >> 16;
	me->pressure = p + ((x1 + x2 + 3791) >> 4);
}

static int bmp180_read_regs(const struct bmp180_st *dev, u8 reg, void *buf, int lenth)
{
	int ret;
	struct i2c_msg msg[2];
	struct i2c_client *client = dev->client;

	//写寄存器地址
	msg[0].addr 	= client->addr;
	msg[0].flags 	= 0;
	msg[0].buf 		= &reg;
	msg[0].len 		= 1;

	//读数据
	msg[1].addr 	= client->addr;
	msg[1].flags 	= I2C_M_RD;
	msg[1].buf 		= buf;
	msg[1].len 		= lenth;

	ret = i2c_transfer(client->adapter , msg, 2);
	if(ret ==2)
	{
		ret =0;
	}
	else
	{
		printk("bmp180_read_regs error\r\n");
		return -EINVAL;
	}

	return 0;
}

static int bmp180_write_regs(const struct bmp180_st *dev, u8 reg, void *buf, int lenth)
{
	int ret;
	u8 sendBuff[256] ={0};
	struct i2c_msg msg;
	struct i2c_client *client = dev->client;

	sendBuff[0] = reg;
	memcpy(&sendBuff[1],buf,lenth);

	//写数据
	msg.addr 	= client->addr;
	msg.flags 	= 0;
	msg.buf 	= sendBuff;
	msg.len 	= lenth+1;

	ret = i2c_transfer(client->adapter, &msg, 1);
	if(ret ==1)
	{
		ret =0;
	}
	else
	{
		printk("bmp180_write_regs error\r\n");
		return -EINVAL;
	}

	return 0;
}

static u8 bmp180_read_reg(const struct bmp180_st *dev, u8 reg)
{
	u8 data;
	bmp180_read_regs(dev, reg, &data, 1);

	return data;
}

static void bmp180_write_reg(const struct bmp180_st *dev, u8 reg, u8 data)
{
	bmp180_write_regs(dev, reg, &data, 1);
}

static int bmp180_getCheckData(struct bmp180_st *dev)
{
	int ret =0;
	u8 checkBuff[22] ={0};	

	ret = bmp180_read_regs(dev, 0xAA, checkBuff, 6);
	if(ret<0)
	{
		printk("bmp180_getCheckData error\r\n");
		return -EINVAL;
	}

	ret = bmp180_read_regs(dev, 0xB0, &checkBuff[6], 16);
	if(ret<0)
	{
		printk("bmp180_getCheckData error\r\n");
		return -EINVAL;
	}

	dev->ac1 = (checkBuff[0]<<8) + checkBuff[1];
	dev->ac2 = (checkBuff[2]<<8) + checkBuff[3]; 
	dev->ac3 = (checkBuff[4]<<8) + checkBuff[5]; 
	dev->ac4 = (checkBuff[6]<<8) + checkBuff[7]; 
	dev->ac5 = (checkBuff[8]<<8) + checkBuff[9]; 
	dev->ac6 = (checkBuff[10]<<8) + checkBuff[11]; 
	dev->b1  = (checkBuff[12]<<8) + checkBuff[13];  
	dev->b2  = (checkBuff[14]<<8) + checkBuff[15]; 
	dev->mb  = (checkBuff[16]<<8) + checkBuff[17]; 
	dev->mc  = (checkBuff[18]<<8) + checkBuff[19]; 
	dev->md  = (checkBuff[20]<<8) + checkBuff[21]; 

	return 0;
}

static ssize_t bmp180_read(struct file *flip, char __user *buff, size_t cnt, loff_t *off)
{
	int ret =0;
	struct bmp180_st *me = flip->private_data;
	u8 checkBuff[5] = {0};
	long ut=0;
	long up=0;
	long data[2]={2};

	bmp180_write_reg(me, 0xF4, 0x2E);
	mdelay(10);
	ret = bmp180_read_regs(me, 0xF6, checkBuff, 2);
	if(ret<0)
	{
		printk("bmp180_getCheckData error\r\n");
		return -EINVAL;
	}

	bmp180_write_reg(me, 0xF4, 0x34+(OSS_QUALITY<<6));
	mdelay(10);
	ret = bmp180_read_regs(me, 0xB0, &checkBuff[2], 3);
	if(ret<0)
	{
		printk("bmp180_getCheckData error\r\n");
		return -EINVAL;
	}
	
	ut = (checkBuff[0]<<8) +checkBuff[1];
	up = ((checkBuff[2]<<16) + (checkBuff[3]<<8) + checkBuff[4])>>(8-OSS_QUALITY);
	bmp085Convert(me, ut, up);
	data[0] = me->temperature;
	data[1] = me->pressure;

	ret = copy_to_user(buff, data, sizeof(data));
	if(ret)
	{
		printk("bmp180_read error\r\n");
		return -EINVAL;
	}

	return 0;
}

static int bmp180_open(struct inode *inode, struct file *flip)
{
	int ret =0;

	//读取传感器校正数据
	ret = bmp180_getCheckData(&bmp180);
	if(ret<0)
	{
		printk("bmp180_open error ret:%d\r\n",ret);
		return -EINVAL;
	}
	
	//保存用户数据
	flip->private_data = &bmp180;

	return 0;
}

static int bmp180_release(struct inode *inode, struct file *flip)
{
	return 0;
}

static const struct file_operations bmp180_fops=
{
	.owner 		= THIS_MODULE,
	.open 		= bmp180_open,
	.release 	= bmp180_release,
	.read 		= bmp180_read,
};

static int bmp180_probe(struct i2c_client *client, const struct i2c_device_id *dev)
{
	int ret = 0;
	
	//申请设备号
	if(bmp180.major)
	{
		bmp180.devID = MKDEV(bmp180.major, 0);
		ret = register_chrdev_region(bmp180.devID, BMP180_NUM, BMP180_NAME);
		if(ret <0)
		{
			printk("register_chrdev_region error\r\n");
			goto chrdev_err;
		}
	}
	else
	{
		ret = alloc_chrdev_region(&bmp180.devID, 0, BMP180_NUM, BMP180_NAME);
		if(ret <0)
		{
			printk("alloc_chrdev_region error\r\n");
			goto chrdev_err;
		}

		bmp180.major = MAJOR(bmp180.devID);
		bmp180.minor = MINOR(bmp180.devID);
	}

	//创建字符设备
	bmp180.cdev.owner = THIS_MODULE;
	cdev_init(&bmp180.cdev, &bmp180_fops);
	ret = cdev_add(&bmp180.cdev, bmp180.devID, BMP180_NUM);
	if(ret <0)
	{
		printk("cdev_add error\r\n");
		goto cdev_err;		
	}

	//创建类
	bmp180.class = class_create(THIS_MODULE, BMP180_NAME);
	if(IS_ERR(bmp180.class))
	{
		printk("class_create error\r\n");
		ret = PTR_ERR(bmp180.class);
		goto class_err;
	}

	//创建设备
	bmp180.device = device_create(bmp180.class, NULL, bmp180.devID, NULL, BMP180_NAME);
	if(IS_ERR(bmp180.device))
	{
		printk("class_create error\r\n");
		ret = PTR_ERR(bmp180.device);
		goto device_err;
	}

	//保存i2c client
	bmp180.client = client;

	printk("bmp180_probe sucess\r\n");
	return 0;

device_err:
	class_destroy(bmp180.class);
class_err:
	cdev_del(&bmp180.cdev);
cdev_err:
	unregister_chrdev_region(bmp180.devID, BMP180_NUM);
chrdev_err:
	return ret;	
}

static int bmp180_remove(struct i2c_client *client)
{
	//释放字符设备
	cdev_del(&bmp180.cdev);
	unregister_chrdev_region(bmp180.devID, BMP180_NUM);
	
	//销毁设备、类
	device_destroy(bmp180.class, bmp180.devID);
	class_destroy(bmp180.class);

	printk("bmp180_remove sucess\r\n");
	return 0;
}

const struct i2c_device_id bmp180_id[]=
{
	{"boshbmp180",0},
	{},
};

const struct of_device_id bmp180_of_match[]=
{
	{.compatible = "boshbmp180"},
	{},
};

static struct i2c_driver bmp180_dev = 
{
	.probe 	= bmp180_probe,
	.remove = bmp180_remove,
	.driver = {
		.owner 	= THIS_MODULE,
		.name 	= "boshbmp180",
		.of_match_table= bmp180_of_match,
	},
	.id_table = bmp180_id,
};

static int __init bmp180_init(void)
{
	return i2c_add_driver(&bmp180_dev);
}

static void __exit bmp180_exit(void)
{
	i2c_del_driver(&bmp180_dev);
}

module_init(bmp180_init);
module_exit(bmp180_exit);
MODULE_AUTHOR("jtb");
MODULE_LICENSE("GPL");

